"""
研究缓存服务
实现多级缓存策略，包括内存缓存和文件缓存
"""

import time
import json
from typing import Any, Optional, Dict, List, Callable
from pathlib import Path
import asyncio
from src.config.settings import settings
from src.utils.logging import get_logger
from src.services.cache_service import CacheService

logger = get_logger(__name__)

class ResearchCache:
    """研究缓存类，实现多级缓存策略"""
    
    def __init__(self, cache_dir: Optional[str] = None):
        """
        初始化研究缓存
        
        Args:
            cache_dir: 缓存目录路径
        """
        cache_dir = cache_dir or f"{settings.CACHE_DIR}/research"
        self.cache_dir = Path(cache_dir)
        self.cache_dir.mkdir(parents=True, exist_ok=True)
        
        # 初始化基础缓存服务
        self.base_cache = CacheService(cache_dir=cache_dir)
        
        # 缓存统计
        self.hits = 0
        self.misses = 0
        
        # 缓存预热相关
        self.preload_functions: List[Callable] = []
        self.preload_data: Dict[str, Any] = {}
        
        # 智能失效策略相关
        self.access_frequency: Dict[str, int] = {}  # 访问频率统计
        self.last_access_time: Dict[str, float] = {}  # 最后访问时间
        
        logger.info(f"研究缓存服务初始化完成，目录: {cache_dir}")
    
    def _generate_cache_key(self, question: str) -> str:
        """
        生成缓存键
        
        Args:
            question: 研究问题
            
        Returns:
            缓存键
        """
        # 使用问题的hash作为缓存键，避免键名过长
        import hashlib
        return hashlib.md5(question.encode('utf-8')).hexdigest()
    
    def get_research_result(self, question: str) -> Optional[Dict[str, Any]]:
        """
        获取研究结果缓存
        
        Args:
            question: 研究问题
            
        Returns:
            研究结果或None
        """
        cache_key = f"research:{self._generate_cache_key(question)}"
        
        # 更新访问统计
        self._update_access_stats(cache_key)
        
        result = self.base_cache.get(cache_key)
        if result is not None:
            self.hits += 1
            logger.debug(f"研究缓存命中: {question}")
            return result
        else:
            self.misses += 1
            logger.debug(f"研究缓存未命中: {question}")
            return None
    
    def set_research_result(self, question: str, result: Dict[str, Any], ttl: Optional[int] = None) -> bool:
        """
        设置研究结果缓存
        
        Args:
            question: 研究问题
            result: 研究结果
            ttl: 存活时间（秒）
            
        Returns:
            是否设置成功
        """
        cache_key = f"research:{self._generate_cache_key(question)}"
        success = self.base_cache.set(cache_key, result, ttl)
        
        if success:
            logger.debug(f"研究结果缓存设置成功: {question}")
        else:
            logger.error(f"研究结果缓存设置失败: {question}")
        
        return success
    
    def _update_access_stats(self, cache_key: str):
        """更新访问统计信息"""
        # 更新访问频率
        self.access_frequency[cache_key] = self.access_frequency.get(cache_key, 0) + 1
        
        # 更新最后访问时间
        self.last_access_time[cache_key] = time.time()
    
    def add_preload_function(self, func: Callable, *args, **kwargs):
        """
        添加预加载函数
        
        Args:
            func: 预加载函数
            *args: 函数参数
            **kwargs: 函数关键字参数
        """
        self.preload_functions.append((func, args, kwargs))
        logger.debug(f"添加预加载函数: {func.__name__}")
    
    async def preload_cache(self):
        """预加载缓存数据"""
        logger.info("开始缓存预热...")
        preload_count = 0
        
        for func, args, kwargs in self.preload_functions:
            try:
                # 执行预加载函数
                if asyncio.iscoroutinefunction(func):
                    result = await func(*args, **kwargs)
                else:
                    result = func(*args, **kwargs)
                
                # 如果返回结果是字典且包含question和result字段，则缓存
                if isinstance(result, dict) and 'question' in result and 'result' in result:
                    question = result['question']
                    cache_result = result['result']
                    if self.set_research_result(question, cache_result):
                        preload_count += 1
                
                logger.debug(f"预加载函数执行成功: {func.__name__}")
                
            except Exception as e:
                logger.error(f"预加载函数执行失败 {func.__name__}: {e}")
        
        logger.info(f"缓存预热完成，预加载 {preload_count} 个项目")
        return preload_count
    
    def get_cache_efficiency(self) -> float:
        """
        获取缓存效率
        
        Returns:
            缓存命中率
        """
        total = self.hits + self.misses
        if total == 0:
            return 0.0
        return self.hits / total
    
    def get_access_stats(self) -> Dict[str, Any]:
        """
        获取访问统计信息
        
        Returns:
            访问统计信息
        """
        return {
            "hits": self.hits,
            "misses": self.misses,
            "efficiency": self.get_cache_efficiency(),
            "access_frequency": self.access_frequency,
            "last_access_time": self.last_access_time
        }
    
    def smart_invalidate(self, max_age: int = 86400, min_frequency: int = 1) -> int:
        """
        智能失效策略
        
        Args:
            max_age: 最大缓存年龄（秒）
            min_frequency: 最小访问频率
            
        Returns:
            失效的缓存数量
        """
        current_time = time.time()
        invalidated_count = 0
        
        # 收集需要失效的缓存键
        to_invalidate = []
        
        for cache_key, last_access in self.last_access_time.items():
            # 检查缓存年龄
            age = current_time - last_access
            
            # 检查访问频率
            frequency = self.access_frequency.get(cache_key, 0)
            
            # 如果缓存太老或者访问频率太低，则失效
            if age > max_age or frequency < min_frequency:
                to_invalidate.append(cache_key)
        
        # 执行失效
        for cache_key in to_invalidate:
            # 从统计数据中移除
            if cache_key in self.access_frequency:
                del self.access_frequency[cache_key]
            if cache_key in self.last_access_time:
                del self.last_access_time[cache_key]
            
            # 从基础缓存中删除
            # 注意：这里我们只从统计数据中移除，不实际删除缓存
            # 因为缓存可能在其他地方使用
            invalidated_count += 1
        
        logger.info(f"智能缓存失效完成，失效 {invalidated_count} 个项目")
        return invalidated_count
    
    def clear_stats(self):
        """清空统计信息"""
        self.hits = 0
        self.misses = 0
        self.access_frequency.clear()
        self.last_access_time.clear()
        logger.info("缓存统计信息已清空")
